package com.xcj.juhe.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xcj.juhe.dto.InitDto;
import com.xcj.juhe.mapper.test1.DeviceMapper;
import com.xcj.juhe.service.InitService;
import com.xcj.juhe.tool.DeviceTool;
import com.xcj.juhe.tool.MyTool;
import com.xcj.juhe.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author xcj
 * @date 2021/5/10 15:19
 */
@Service
@Slf4j
public class InitServiceImpl implements InitService {

    private static String URL = "http://test-api.gamedachen.com/device/init";

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    MyTool myTool = new MyTool();

    @Override
    public ResultVO addInitDevice(InitDto initDto) {
        long startTime = new Date().getTime();
        Map map = new HashMap();
        int sum = 0;

        map.put("sdkId", initDto.getSdkId());
        map.put("dcChannelId", 3);
        map.put("versionNo", 31);
        map.put("subChannelId", 0);
        map.put("deviceFactory", "HUAWEI");
        map.put("deviceMac", "test:81:65:18:e6:67");
        map.put("appId", initDto.getAppId());
        map.put("channelId", initDto.getChannelId());
        map.put("deviceOs", 1);
        map.put("osVersion", "android5.1.1");
        map.put("deviceModel", "SEA-AL10");
        map.put("deviceDpi", "720×1280");
        map.put("dcProductId", "2225");

        for (int i = 0; i < initDto.getNumber(); i++) {
            map.put("deviceId", this.getOnlyOneDeviceId());
            if (this.callInit(map, initDto.getTime()))
                sum++;
        }

        ResultVO resultVO = new ResultVO();
        if (sum > 0) {
            resultVO.setCode(200);
            resultVO.setMsg("success");
            resultVO.setData(sum);
        } else {
            resultVO.setCode(100);
            resultVO.setMsg("都初始化失败了");
        }
        long endTime = new Date().getTime();
        System.out.println("此次处理总耗时:"+ (endTime - startTime)/1000);
        return resultVO;
    }

    /**
     * 使用线程池优化过的初始化设备
     * @param initDto
     * @return
     */
    @Override
    public ResultVO addInitDevice2(InitDto initDto) {
        long startTime = new Date().getTime();
        Map map = new HashMap();
        AtomicInteger sum = new AtomicInteger(0);
        map.put("sdkId", initDto.getSdkId());
        map.put("dcChannelId", 3);
        map.put("versionNo", 31);
        map.put("subChannelId", 0);
        map.put("deviceFactory", "HUAWEI");
        map.put("deviceMac", "test:81:65:18:e6:67");
        map.put("appId", initDto.getAppId());
        map.put("channelId", initDto.getChannelId());
        map.put("deviceOs", 1);
        map.put("osVersion", "android5.1.1");
        map.put("deviceModel", "SEA-AL10");
        map.put("deviceDpi", "720×1280");
        map.put("dcProductId", "2225");

        //倒数，此处用于多线程控制（全部线程执行完再继续执行）
        CountDownLatch countDownLatch = new CountDownLatch(initDto.getNumber());

        //todo 循环执行业务逻辑
        for (int i = 0; i < initDto.getNumber(); i++) {
            map.put("deviceId", getOnlyOneDeviceId());
            //todo 使用线程池
            threadPoolTaskExecutor.execute(()->{
                if (callInit(map, initDto.getTime())){
                    sum.getAndAdd(1);
                }
                countDownLatch.countDown();
            });
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ResultVO resultVO = new ResultVO();
        if (sum.get()>0) {
            resultVO.setCode(200);
            resultVO.setMsg("success");
            resultVO.setData(sum);
        } else {
            resultVO.setCode(100);
            resultVO.setMsg("都初始化失败了");
        }
        long endTime = new Date().getTime();
        System.out.println("此次处理总耗时:"+ (endTime - startTime)/1000);
        return resultVO;
    }

    //调用初始化
    private Boolean callInit(Map map, String time) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<Map<String, Object>> request = new HttpEntity<Map<String, Object>>(map, headers);

        ResponseEntity<String> entity = restTemplate.postForEntity(URL, request, String.class);

        String body = entity.getBody();

        String deviceId = (String) map.get("deviceId");
        log.info("{}初始化了，接口响应：{}", deviceId, body);

        JSONObject json = JSON.parseObject(body);
        String code = json.getString("code");

        if (code.equals("200")) {

            //不是当天就更新初始化设备信息
            if (!myTool.isNowDay(time)){
                String timeStr = myTool.StringToTime(time);

                if (updateDeviceTime(deviceId, timeStr)){
                    log.info("{}更新时间{}成功。",deviceId,timeStr);
                    return true;
                }else {
                    log.error("{}更新时间{}失败！！！",deviceId,timeStr);
                    return false;
                }
            }else {
                return true;
            }
        } else {
            log.error("初始化失败:{}", body);
            return false;
        }
    }

    /**
     * mint_device(唯一，新增设备记录表)、mint_device_log(不唯一，设备初始化日志记录表)
     *
     * @param deviceId
     * @param time
     * @return
     */
    private boolean updateDeviceTime(String deviceId, String time) {

        int i = deviceMapper.updateDeviceTimeByDeviceId(deviceId, time);
        int j = deviceMapper.updateDeviceLogTimeByDeviceId(deviceId, time);

        return (i > 0 && j > 0);
    }

    //获取唯一新的设备号
    private String getOnlyOneDeviceId() {
        String d = new DeviceTool().makeDeviceId();
        while (deviceMapper.findDeviceId(d) != null) {
            log.warn("设备号重复，正在重新生成设备号。{}", d);
            this.getOnlyOneDeviceId();
        }
        return d;
    }
}
